/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import fvaswing.components.tree.FvAbstractTreeNode;
import fvaswing.components.tree.FvTreeItem;

/**
 * Tree node for {@link fvaswing.components.FvTree} componant.
 *
 * @author Romain Ecarnot
 */
class fvaswing.components.tree.FvTreeNode extends FvAbstractTreeNode
{
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
		
    /**
     * Creates a tree node with no parent, no children, initialized with
     * the specified user object, and that allows children only if
     * specified.
     * 
     * @param userObject an Object provided by the user that constitutes
     *        the node's data
     * @param allowsChildren (optional)if true, the node is allowed to have child
     *        nodes -- otherwise, it is always a leaf node. Default is true.
     * @param draggable Node is draggable or not ( override tree behaviour for this specific node )
     * @param editable Node is editable or not ( override tree behaviour for this specific node )
     */
    public function FvTreeNode( userObject : FvTreeItem, allowsChildren : Boolean, draggable : Boolean, editable : Boolean, deletable : Boolean )
    {
		super( userObject, allowsChildren, draggable, editable, deletable );
    }
	
	/**
     * Sets the user object for this node to <code>userObject</code>.
     *
     * @param	userObject	the Object that constitutes this node's 
     * user-specified data
     */
    public function setUserObject( userObject : FvTreeItem ) : Void
    {
		_userObject = userObject;
    }
	
    /**
     * Returns this node's user object.
     */
    public function getUserObject() : FvTreeItem
    {	
		return FvTreeItem( _userObject );
    }
    
    /**
     * Removes <code>newChild</code> from its present parent (if it has a
     * parent), sets the child's parent to this node, and then adds the child
     * to this node's child array at index <code>childIndex</code>.
     * <code>newChild</code> must not be null and must not be an ancestor of
     * this node.
     *
     * @param	newChild	the FvTreeNode to insert under this node
     * @param	childIndex	the index in this node's child array
     *				where this node is to be inserted
     * @exception	Error	if
     *				<code>newChild</code> is null or is an ancestor of this node, 
     *				or if <code>childIndex</code> is out of bounds, or if this 
     *				node does not allow children
     * @see	#isNodeDescendant
     */
    public function insert( newChild : FvTreeNode, childIndex : Number ) : Void
    {
		super.insert( newChild, childIndex );
    }

    /**
     * Sets this node's parent to <code>newParent</code> but does not 
     * change the parent's child array.  This method is called from
     * <code>insert()</code> and <code>remove()</code> to
     * reassign a child's parent, it should not be messaged from anywhere
     * else.
     *
     * @param	newParent	this node's new parent
     */
    public function setParent( newParent : FvTreeNode ) : Void
    {
		super.setParent( newParent );
    }

    /**
     * Returns this node's parent or null if this node has no parent.
     *
     * @return	this node's parent TreeNode, or null if this node has no parent
     */
    public function getParent() : FvTreeNode
    {
		return FvTreeNode( _parent );
    }
	
    /**
     * Returns the child at the specified index in this node's child array.
     *
     * @param	index	an index into this node's child array
     * @exception	ArrayIndexOutOfBoundsException	if <code>index</code>
     *						is out of bounds
     * @return	the TreeNode in this node's child array at  the specified index
     */
    public function getChildAt( index : Number ) : FvTreeNode
    {
		return FvTreeNode( super.getChildAt( index ) );
    }
	
    /**
     * Returns the index of the specified child in this node's child array.
     * If the specified node is not a child of this node, returns
     * <code>-1</code>.  This method performs a linear search and is O(n)
     * where n is the number of children.
     *
     * @param	aChild	the FvTreeNode to search for among this node's children
     * @return	an int giving the index of the node in this node's child 
     *          array, or <code>-1</code> if the specified node is a not
     *          a child of this node
     */
    public function getIndex( aChild : FvTreeNode ) : Number
    {
		return super.getIndex( aChild );
	}
  
    /**
     * Removes <code>aChild</code> from this node's child array, giving it a
     * null parent.
     *
     * @param	aChild	a child of this node to remove
     */
    public function remove( aChild : FvTreeNode ) : Void 
    {
		super.remove( aChild );
    }
	
    /**
     * Removes <code>newChild</code> from its parent and makes it a child of
     * this node by adding it to the end of this node's child array.
     *
     * @param	newChild	node to add as a child of this node
     */
    public function append( newChild : FvTreeNode ) : Void 
    {
		super.append( newChild );
    }
	
    /**
     * Returns true if <code>anotherNode</code> is an ancestor of this node
     * -- if it is this node, this node's parent, or an ancestor of this
     * node's parent.  (Note that a node is considered an ancestor of itself.)
     * If <code>anotherNode</code> is null, this method returns false.  This
     * operation is at worst O(h) where h is the distance from the root to
     * this node.
     *
     * @param	anotherNode	node to test as an ancestor of this node
     * @return	true if this node is a descendant of <code>anotherNode</code>
     */
    public function isNodeAncestor( anotherNode : FvTreeNode ) : Boolean 
    {
		return super.isNodeAncestor( anotherNode );
    }

    /**
     * Returns true if <code>anotherNode</code> is a descendant of this node
     * -- if it is this node, one of this node's children, or a descendant of
     * one of this node's children.  Note that a node is considered a
     * descendant of itself.  If <code>anotherNode</code> is null, returns
     * false.  This operation is at worst O(h) where h is the distance from the
     * root to <code>anotherNode</code>.
     *
     * @param	anotherNode	node to test as descendant of this node
     * @return	true if this node is an ancestor of <code>anotherNode</code>
     */
    public function isNodeDescendant( anotherNode : FvTreeNode ) : Boolean 
    {
		return super.isNodeDescendant( anotherNode );
    }
	
    /**
     * Returns the nearest common ancestor to this node and <code>aNode</code>.
     * Returns null, if no such ancestor exists -- if this node and
     * <code>aNode</code> are in different trees or if <code>aNode</code> is
     * null.  A node is considered an ancestor of itself.
     *
     * @param	aNode	node to find common ancestor with
     * @return	nearest ancestor common to this node and <code>aNode</code>,
     *		or null if none
     */
    public function getSharedAncestor( aNode : FvTreeNode ) : FvTreeNode 
    {
		return FvTreeNode( super.getSharedAncestor( aNode ) );
    }

    /**
     * Returns true if and only if <code>aNode</code> is in the same tree
     * as this node.  Returns false if <code>aNode</code> is null.
     *
     * @see	#getSharedAncestor
     * @see	#getRoot
     * @return	true if <code>aNode</code> is in the same tree as this node;
     *		false if <code>aNode</code> is null
     */
    public function isNodeRelated( aNode : FvTreeNode ) : Boolean 
    {
		return super.isNodeRelated( aNode );
    }
	
    /**
     * Returns the root of the tree that contains this node.  The root is
     * the ancestor with a null parent.
     *
     * @return	the root of the tree that contains this node
     */
    public function getRoot() : FvTreeNode 
    {
		return FvTreeNode( super.getRoot() );
    }
	
    /**
     * Returns the node that follows this node in a preorder traversal of this
     * node's tree.  Returns null if this node is the last node of the
     * traversal.  This is an inefficient way to traverse the entire tree; use
     * an enumeration, instead.
     *
     * @see	#preorderEnumeration
     * @return	the node that follows this node in a preorder traversal, or
     *		null if this node is last
     */
    public function getNextNode() : FvTreeNode 
    {
		return FvTreeNode( super.getNextNode() );
    }
	
    /**
     * Returns the node that precedes this node in a preorder traversal of
     * this node's tree.  Returns <code>null</code> if this node is the
     * first node of the traversal -- the root of the tree. 
     * This is an inefficient way to
     * traverse the entire tree; use an enumeration, instead.
     *
     * @see	#preorderEnumeration
     * @return	the node that precedes this node in a preorder traversal, or
     *		null if this node is the first
     */
    public function getPreviousNode() : FvTreeNode 
    {
		return FvTreeNode( super.getPreviousNode() );
    }
	
    /**
     * Creates and returns an enumeration that follows the path from
     * <code>ancestor</code> to this node.  The enumeration's
     * <code>nextElement()</code> method first returns <code>ancestor</code>,
     * then the child of <code>ancestor</code> that is an ancestor of this
     * node, and so on, and finally returns this node.  Creation of the
     * enumeration is O(m) where m is the number of nodes between this node
     * and <code>ancestor</code>, inclusive.  Each <code>nextElement()</code>
     * message is O(1).<P>
     *
     * Modifying the tree by inserting, removing, or moving a node invalidates
     * any enumerations created before the modification.
     *
     * @see		#isNodeAncestor()
     * @see		#isNodeDescendant()
     * @exception	IllegalArgumentException if <code>ancestor</code> is
     *						not an ancestor of this node
     * @return	an enumeration for following the path from an ancestor of
     *		this node to this one
     */
    public function pathFromAncestorEnumeration( ancestor : FvTreeNode ) : Array 
    {
    	return pathFromAncestorEnumeration( ancestor );
    }

    /**
     * Returns true if <code>aNode</code> is a child of this node.  If
     * <code>aNode</code> is null, this method returns false.
     *
     * @return	true if <code>aNode</code> is a child of this node; false if 
     *  		<code>aNode</code> is null
     */
    public function isNodeChild( aNode : FvTreeNode ) : Boolean 
    {
		return super.isNodeChild( aNode );
    }

    /**
     * Returns this node's first child.
     *
     * @return	the first child of this node, null if this node has no children
     */
    public function getFirstChild() : FvTreeNode 
    {
		return FvTreeNode( super.getFirstChild() );
    }

    /**
     * Returns this node's last child.
     *
     * @return	the last child of this node, null if this node has no children
     */
    public function getLastChild() : FvTreeNode 
    {
		return FvTreeNode( super.getLastChild() );
    }

    /**
     * Returns the child in this node's child array that immediately
     * follows <code>aChild</code>, which must be a child of this node.  If
     * <code>aChild</code> is the last child, returns null.  This method
     * performs a linear search of this node's children for
     * <code>aChild</code> and is O(n) where n is the number of children; to
     * traverse the entire array of children, use an enumeration instead.
     *
     * @see		#children()
     * @exception	Error if <code>aChild</code> is
     *					null or is not a child of this node
     * @return	the child of this node that immediately follows
     *		<code>aChild</code>
     */
    public function getChildAfter( aChild : FvTreeNode ) : FvTreeNode 
    {
		return FvTreeNode( super.getChildAfter( aChild ) );
    }
	
    /**
     * Returns the child in this node's child array that immediately
     * precedes <code>aChild</code>, which must be a child of this node.  If
     * <code>aChild</code> is the first child, returns null.  This method
     * performs a linear search of this node's children for <code>aChild</code>
     * and is O(n) where n is the number of children.
     *
     * @exception	IllegalArgumentException if <code>aChild</code> is null
     *						or is not a child of this node
     * @return	the child of this node that immediately precedes
     *		<code>aChild</code>
     */
    public function getChildBefore( aChild : FvTreeNode ) : FvTreeNode 
    {
		return FvTreeNode( super.getChildBefore( aChild ) );
    }

    /**
     * Returns true if <code>anotherNode</code> is a sibling of (has the
     * same parent as) this node.  A node is its own sibling.  If
     * <code>anotherNode</code> is null, returns false.
     *
     * @param	anotherNode	node to test as sibling of this node
     * @return	true if <code>anotherNode</code> is a sibling of this node
     */
    public function isNodeSibling( anotherNode : FvTreeNode ) : Boolean 
    {
		return super.isNodeSibling( anotherNode );
    }
	
    /**
     * Returns the next sibling of this node in the parent's children array.
     * Returns null if this node has no parent or is the parent's last child.
     * This method performs a linear search that is O(n) where n is the number
     * of children; to traverse the entire array, use the parent's child
     * enumeration instead.
     *
     * @see	#children
     * @return	the sibling of this node that immediately follows this node
     */
    public function getNextSibling() : FvTreeNode 
    {
		return FvTreeNode( super.getNextSibling() );
    }

    /**
     * Returns the previous sibling of this node in the parent's children
     * array.  Returns null if this node has no parent or is the parent's
     * first child.  This method performs a linear search that is O(n) where n
     * is the number of children.
     *
     * @return	the sibling of this node that immediately precedes this node
     */
    public function getPreviousSibling() : FvTreeNode
    {
		return FvTreeNode( super.getPreviousSibling() );
    }
	
    /**
     * Finds and returns the first leaf that is a descendant of this node --
     * either this node or its first child's first leaf.
     * Returns this node if it is a leaf.
     *
     * @return	the first leaf in the subtree rooted at this node
     */
    public function getFirstLeaf() : FvTreeNode 
    {
		return FvTreeNode( super.getFirstLeaf() );
    }

    /**
     * Finds and returns the last leaf that is a descendant of this node --
     * either this node or its last child's last leaf. 
     * Returns this node if it is a leaf.
     *
     * @see	#isLeaf()
     * @see	#isNodeDescendant()
     * @return	the last leaf in the subtree rooted at this node
     */
    public function getLastLeaf() : FvTreeNode
    {
		return FvTreeNode( super.getLastLeaf() );
    }

    /**
     * Returns the leaf after this node or null if this node is the
     * last leaf in the tree.
     * <p>
     * In this implementation of the <code>MutableNode</code> interface,
     * this operation is very inefficient. In order to determine the
     * next node, this method first performs a linear search in the 
     * parent's child-list in order to find the current node. 
     * <p>
     * That implementation makes the operation suitable for short
     * traversals from a known position. But to traverse all of the 
     * leaves in the tree, you should use <code>depthFirstEnumeration</code>
     * to enumerate the nodes in the tree and use <code>isLeaf</code>
     * on each node to determine which are leaves.
     *
     * @return	returns the next leaf past this node
     */
    public function getNextLeaf() : FvTreeNode
    {
		return FvTreeNode( super.getNextLeaf() );
    }

    /**
     * Returns the leaf before this node or null if this node is the
     * first leaf in the tree.
     * <p>
     * In this implementation of the <code>MutableNode</code> interface,
     * this operation is very inefficient. In order to determine the
     * previous node, this method first performs a linear search in the 
     * parent's child-list in order to find the current node. 
     * <p>
     * That implementation makes the operation suitable for short
     * traversals from a known position. But to traverse all of the 
     * leaves in the tree, you should use <code>depthFirstEnumeration</code>
     * to enumerate the nodes in the tree and use <code>isLeaf</code>
     * on each node to determine which are leaves.
     *
     * @return	returns the leaf before this node
     */
    public function getPreviousLeaf() : FvTreeNode
    {
		return FvTreeNode( super.getPreviousLeaf() );
    }	
    
    /**
     * Returns a duplicated node.
     */
    public function duplicate() : FvTreeNode
   	{
   		return new FvTreeNode( null, _allowsChildren, _isDraggable, _isEditable, _isDeletable );
   	}  
}